package org.jactao.rpc;

import com.esotericsoftware.reflectasm.MethodAccess;
import com.lmax.disruptor.EventHandler;
import org.jactao.common.LException;
import org.jactao.common.LRequest;
import org.jactao.common.LResponse;

import java.lang.reflect.Method;

/**
 * Created by fanzetao on 2018/4/3.
 */
public class LRequestEventHandler implements EventHandler<LRequestEvent> {

    @Override
    public void onEvent(LRequestEvent requestEvent, long sequence, boolean endOfBatch) throws Exception {

        LResponse response = new LResponse();
        LRequest request = requestEvent.getRequest();

        response.setRequestId(request.getRequestId());

        Object res = null;
        Throwable throwable = null;

        try {
            //ReflectASM 反射调用本地方法
            Object target = LContainer.getInstance().getService(request.getClazz().getName());
            if(target == null) {
                response.setThrowable(new LException("not register " + request.getClazz().getName() + " interface impl"));
                requestEvent.getChannel().writeAndFlush(response);
                return;
            }

            boolean methodFound = false;
            Method[] methods = target.getClass().getMethods();
            for(Method method : methods) {
                if(method.getName().equals(request.getMethod())) {
                    methodFound = true;
                    break;
                }
            }

            if(!methodFound) {
                response.setThrowable(new LException("not register " + request.getMethod() + " method"));
                requestEvent.getChannel().writeAndFlush(response);
                return;
            }

            MethodAccess access = MethodAccess.get(request.getClazz());
            int index = access.getIndex(request.getMethod(), request.getParameterTypes());

            long start = System.currentTimeMillis();
            res = access.invoke(target, index, request.getParams());
            request.setRequestTime(System.currentTimeMillis() - start);
        }catch (Exception e) {
            e.printStackTrace();
            throwable = e;
        }

        response.setResponse(res);
        response.setThrowable(throwable);
        requestEvent.getChannel().writeAndFlush(response);
    }
}
